﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Jb.Domain;
using Jb.Web.ViewModels;
using Jb.Common.Extensions;
using AutoMapper;
using System.Text;
using System.Configuration;
using Jb.Common.DB;

namespace Jb.Web.Utility
{
    public class BootStrapper
    {
        /// <summary>
        /// Configures the AutoMapper with appropriate Domain DataModel and UI ViewModel types
        /// </summary>
        public static void ConfigureTypeMappings()
        {
            ///Mapper needed for auto converters
            DateTimeToStringConverter dateToString = new DateTimeToStringConverter();
            StringToDateTimeConverter stringToDateTime = new StringToDateTimeConverter();
            StringToNullableDateTimeConverter stringToNullableDateTimeConverter = new StringToNullableDateTimeConverter();

            Mapper.CreateMap<String, DateTime>().ConvertUsing(stringToDateTime);
            Mapper.CreateMap<String, DateTime?>().ConvertUsing(stringToNullableDateTimeConverter);
            Mapper.CreateMap<DateTime, String>().ConvertUsing(dateToString);

            StringToBoolean stringToBoolean = new StringToBoolean();
            BooleanToString booleanToString = new BooleanToString();
            Mapper.CreateMap<String, bool>().ConvertUsing(stringToBoolean);
            Mapper.CreateMap<bool, String>().ConvertUsing(booleanToString);

            IntToNullableInt intToNullableInt = new IntToNullableInt();
            Mapper.CreateMap<int, int?>().ConvertUsing(intToNullableInt);

            ///AutoMapper configuration for IndustryType Entity
            Mapper.CreateMap<IndustryType, IndustryTypeViewModel>();
            Mapper.CreateMap<IndustryTypeViewModel, IndustryType>();

            //Address Mapper
            Mapper.CreateMap<Address, AddressViewModel>();
            Mapper.CreateMap<AddressViewModel, Address>()
                .ForMember(dest => dest.CreatedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedBy, source => source.Ignore()); 

            ///User Mapper
            Mapper.CreateMap<User, UserViewModel>();
            Mapper.CreateMap<UserViewModel, User>();

            ///User Mapper
            Mapper.CreateMap<Group, GroupViewModel>();
            Mapper.CreateMap<GroupViewModel, Group>();

            ///Product Category Mapper
            Mapper.CreateMap<Category, CategoryViewModel>();
            Mapper.CreateMap<CategoryViewModel, Category>()
                .ForMember(dest => dest.ActiveJobCount, source => source.Ignore())
                .ForMember(dest => dest.UrlName, source => source.Ignore())
                .ForMember(dest => dest.ChildCategories, source => source.Ignore())
                .ForMember(dest => dest.ParentCategory, source => source.Ignore());

            ///Company Mapper
            Mapper.CreateMap<Company, CompanyViewModel>();
            Mapper.CreateMap<CompanyViewModel, Company>()
                .ForMember(dest => dest.Rating, source => source.Ignore())
                .ForMember(dest => dest.ActivationKey, source => source.Ignore())
                .ForMember(dest => dest.IsActive, source => source.Ignore())                
                .ForMember(dest => dest.CreatedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                .ForMember(dest => dest.Address, source => source.Ignore());

            ///Contact Mapper
            Mapper.CreateMap<Contact, ContactViewModel>();
            Mapper.CreateMap<ContactViewModel, Contact>()
                .ForMember(dest => dest.CreatedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore());
                //.ForMember(dest => dest.Address.CreatedOn, source => source.UseDestinationValue());

            ///Content Mapper
            Mapper.CreateMap<Content, ContentViewModel>();
            Mapper.CreateMap<ContentViewModel, Content>()
                .ForMember(dest => dest.CreatedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedBy, source => source.Ignore())
                .ForMember(dest => dest.Url, source => source.Ignore());

            //Job Mapper
            Mapper.CreateMap<Job, JobViewModel>();
            Mapper.CreateMap<JobViewModel, Job>()
                .ForMember(dest => dest.JobEducations, source => source.Ignore())
                .ForMember(dest => dest.JobSkills, source => source.Ignore())
                .ForMember(dest => dest.IsFeatured, source => source.Ignore());

            //Skill Mapper
            Mapper.CreateMap<Skill, SkillViewModel>();
            Mapper.CreateMap<SkillViewModel, Skill>();

            //Education Mapper
            Mapper.CreateMap<Education, EducationViewModel>();
            Mapper.CreateMap<EducationViewModel, Education>();

            //Coverletter Mapper
            Mapper.CreateMap<CoverLetter, CoverLetterViewModel>();
            Mapper.CreateMap<CoverLetterViewModel, CoverLetter>();
            
            //JobLevel Mapper
            Mapper.CreateMap<JobLevel, JobLevelViewModel>();
            Mapper.CreateMap<JobLevelViewModel, JobLevel>();

            //JobTemplate Mapper
            Mapper.CreateMap<JobTemplate, JobTemplateViewModel>();
            Mapper.CreateMap<JobTemplateViewModel, JobTemplate>();

            //JobSeeker Mapper
            Mapper.CreateMap<JobSeeker, JobSeekerViewModel>();
                //.ForMember(dest => dest.CreatedOn, source => source.Ignore())
                //.ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                //.ForMember(dest => dest.ModifiedBy, source => source.Ignore());
            Mapper.CreateMap<JobSeekerViewModel, JobSeeker>()
                .ForMember(dest => dest.ActivationKey, source => source.Ignore())
                .ForMember(dest => dest.CreatedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                .ForMember(dest => dest.ModifiedBy, source => source.Ignore())
                .ForMember(dest => dest.IsActive, source => source.Ignore())
                .ForMember(dest => dest.Address, source => source.Ignore());

            ///Resume Mapping
            Mapper.CreateMap<Resume, ResumeViewModel>();
            Mapper.CreateMap<ResumeViewModel, Resume>()
                .ForMember(dest => dest.ModifiedOn, source => source.Ignore())
                .ForMember(dest => dest.FileName, source => source.Ignore());

            ///Package Mapping
            Mapper.CreateMap<Package, PackageViewModel>();
            Mapper.CreateMap<PackageViewModel, Package>()
                .ForMember(dest => dest.Modified, source => source.Ignore())
                .ForMember(dest => dest.Created, source => source.Ignore());

            ///Package Subscription Mapping
            Mapper.CreateMap<PackageSubscription, PackageSubscriptionViewModel>();
            Mapper.CreateMap<PackageSubscriptionViewModel, PackageSubscription>();

            ///JobApplication Mapping
            Mapper.CreateMap<JobApplication, JobApplicationViewModel>();
            Mapper.CreateMap<JobApplicationViewModel, JobApplication>()
                .ForMember(dest => dest.AppliedOn, source => source.Ignore())
                .ForMember(dest => dest.HasRead, source => source.Ignore())
                .ForMember(dest => dest.HasShortListed, source => source.Ignore())
                .ForMember(dest => dest.IsDeleted, source => source.Ignore())
                .ForMember(dest => dest.Ranking, source => source.Ignore());

            ///InterviewRequest Mapping
            Mapper.CreateMap<InterviewRequest, InterviewRequestViewModel>();
            Mapper.CreateMap<InterviewRequestViewModel, InterviewRequest>()
                .ForMember(dest => dest.InvitedOn, source => source.Ignore());

            ///SavedSearch Mapping
            Mapper.CreateMap<SavedSearch, SavedSearchViewModel>();
            Mapper.CreateMap<SavedSearchViewModel, SavedSearch>();

            #region LGL Mappings
            ///LGL Mappings
            //Mapper.CreateMap<ViewModels.LGL.Category.Category, ViewModels.LGL.Product.Product>();
            #endregion LGL Mapping
        }

        /// <summary>
        /// Caches the User Groups in the Application Context
        /// </summary>
        public static void SetUserRoles()
        {
            JbEntities context = new JbEntities();
            if (context.IsConnected())
            {
                var groups = context.Groups;
                StringBuilder sb = new StringBuilder();
                foreach (Group group in groups)
                {
                    if (sb.Length == 0)
                        sb.Append(group.Name);
                    else
                        sb.AppendFormat(",{0}", group.Name);
                }
                Jb.Common.Authentication.AppAuthorizeAttribute.UserRoles = sb.ToString();
            }
        }

        public static void PrepareDomainUtility()
        {
            Jb.Common.Mail.MailManager.SmtpHost = ConfigReader.SmtpHost;
            Jb.Common.Mail.MailManager.SmtpPort = ConfigReader.SmtpPort;
            Jb.Common.Extensions.StringExtensions.DateTimeFormatForUI = ConfigReader.CSharpCalendarDateFormat;

            ///Initialize Lucene Index Directories
            Jb.Search.SearchConstants.ResumeIndexDirectory = HttpContext.Current.Server.MapPath(AppConstants.Directories.LUCENE_RESUME_INDEX);
            Jb.Search.SearchConstants.JobIndexDirectory = HttpContext.Current.Server.MapPath(AppConstants.Directories.LUCENE_JOB_INDEX);
            Jb.Search.SearchConstants.ResumeDirectory = HttpContext.Current.Server.MapPath(AppConstants.Directories.RESUMES);
        }

        /// <summary>
        /// Sends Error email to the configured ErrorEmail receiver in AppSettings.config
        /// </summary>
        /// <param name="ex"></param>
        public static void SendErrorEmail(Exception ex)
        {
            if (ex != null)
            {
                if (ex is System.Threading.ThreadAbortException)
                    return;

                StringBuilder template = new StringBuilder(WebUtil.ReadEmailTemplate(AppConstants.EmailTemplate.COMMON));
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("Dear Admin,<br/>An unhandled exception occured in <a href='{0}'>{0}</a>. Check the error details below.<br/>", WebUtil.GetDomainAddress());
                sb.AppendFormat("<b>URL:</b> {0}<br/>", HttpContext.Current.Request.Url.AbsoluteUri);
                if (HttpContext.Current.Request.UrlReferrer != null)
                    sb.AppendFormat("<b>Url Referrer:</b> {0}<br/>", HttpContext.Current.Request.UrlReferrer.AbsoluteUri);
                sb.AppendFormat("<b>Method:</b> {0}<br/>", HttpContext.Current.Request.HttpMethod);
                sb.AppendFormat("<b>User Agent:</b> {0}<br/>", HttpContext.Current.Request.UserAgent);
                if (SessionCache.CurrentUser != null)
                    sb.AppendFormat("<b>User name:</b> {0} <b>User ID:</b>{1}<br/>", SessionCache.CurrentUser.UserName, SessionCache.CurrentUser.ID);
                if (ex.InnerException == null)
                {
                    sb.AppendFormat("<h2 style='color:maroon;'><i>{0}</i></h2>", ex.Message);
                    sb.AppendFormat("<b><u>Stack Trace:</u></b><br/>{0}<br/>", ex.StackTrace);
                }
                else
                {
                    sb.AppendFormat("<h2 style='color:maroon;'><i>{0}</i></h2>", ex.InnerException.Message);
                    if (ex.InnerException.StackTrace.IsNullOrEmpty())
                        sb.AppendFormat("<b><u>Stack Trace:</u></b><br/>{0}<br/>", ex.StackTrace);
                    else
                        sb.AppendFormat("<b><u>InnerException Stack Trace:</u></b><br/>{0}<br/>", ex.InnerException.StackTrace);
                }
                template.Replace(AppConstants.ETConstants.MESSAGE, sb.ToString());
                template.Replace(AppConstants.ETConstants.DOMAIN, WebUtil.GetDomainAddress());
                String subject = String.Format("Error occured in {0}", WebUtil.GetDomainAddress().Replace("http://", String.Empty));
                Console.Write(template.ToString());
                WebUtil.SendMail(ConfigReader.SmtpFromEmail, ConfigReader.ErrorEmail, String.Empty, String.Empty, subject, template.ToString());
            }
        }
    }

    #region  Value Converters
    /// <summary>
    /// Used to Convert String DateTime to DateTime Object
    /// </summary>
    public class StringToDateTimeConverter : ITypeConverter<String, DateTime>
    {       
        public DateTime Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return DateTime.MinValue;
            String sourceValue = ((String)context.SourceValue);
            return sourceValue.IsEmpty() ? DateTime.MinValue : sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
        }
    }
    public class StringToNullableDateTimeConverter : ITypeConverter<String, DateTime?>
    {
        public DateTime? Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return null; //DateTime.MinValue;
            String sourceValue = ((String)context.SourceValue);
            if (sourceValue.IsEmpty())
                return null;
            return sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
            //return sourceValue.IsEmpty() ? null : sourceValue.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
        }
    }

    /// <summary>
    /// Used to Convert DateTime object to String, that will be shown to the UI for edit
    /// </summary>
    public class DateTimeToStringConverter : ITypeConverter<DateTime, String>
    {
        public String Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return String.Empty;

            DateTime sourceValue = ((DateTime)context.SourceValue);
            return sourceValue == DateTime.MinValue ? String.Empty : sourceValue.ToString(ConfigReader.CSharpCalendarDateFormat);
        }
    }

    public class StringToBoolean : ITypeConverter<String, Boolean>
    {
        public bool Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return false;

            return NullHandler.GetString(context.SourceValue).ToBoolean();            
        }
    }
    public class BooleanToString : ITypeConverter<bool, String>
    {
        public string Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return String.Empty;

            return context.SourceValue.ToString();
        }
    }

    public class IntToNullableInt : ITypeConverter<int, int?>
    {
        public int? Convert(ResolutionContext context)
        {
            if (context.SourceValue == null)
                return null;
            
            if (NullHandler.GetInt(context.SourceValue) == 0)
                return null;

            return NullHandler.GetInt(context.SourceValue);
        }
    }
    
    #endregion Value Converters
}